package org.xbdframework.jdbc.core.support;

import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import org.xbdframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;

/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}实现，
 * 用以为属性{@code DataSource}、{@code JdbcTemplate}、{@code NamedParameterJdbcTemplate}自动赋值.
 * <p>
 * {@code DataSource} 和 {@code JdbcTemplate} 任选其一赋值。如均赋值，{@link JdbcDaoSupport}会做判断逻辑，
 * 判断{@code DataSource} 和 {@code JdbcTemplate}中的{@code DataSource}是否相同，如不相同，
 * 会舍弃为其赋值的{@code JdbcTemplate}，从而基于{@code DataSource}创建新的{@code JdbcTemplate}.
 * <p>
 * Note: {@code NamedParameterJdbcTemplate}可设置为空，此时，框架会基于{@code JdbcTemplate}创建新的
 * {@code NamedParameterJdbcTemplate}实例.
 *
 * @author 刘明磊
 * @since 4.3
 * @see org.springframework.beans.factory.config.BeanPostProcessor
 * @see org.springframework.jdbc.core.support.JdbcDaoSupport
 * @see org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport
 * @see NamedParameterJdbcDaoSupport
 */
public class JdbcDaoBeanPostProcessor implements BeanPostProcessor, InitializingBean {

	private DataSource dataSource;

	private JdbcTemplate jdbcTemplate;

	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	public JdbcDaoBeanPostProcessor(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public JdbcDaoBeanPostProcessor(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public JdbcDaoBeanPostProcessor(JdbcTemplate jdbcTemplate,
			NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (this.dataSource == null && this.jdbcTemplate == null) {
			throw new IllegalArgumentException(
					"'dataSource' or 'jdbcTemplate' is required");
		}
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		if (bean instanceof JdbcDaoSupport
				|| bean instanceof org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport) {
			if (this.dataSource != null) {
				((JdbcDaoSupport) bean).setDataSource(this.dataSource);
			}
			else if (this.jdbcTemplate != null) {
				((JdbcDaoSupport) bean).setJdbcTemplate(this.jdbcTemplate);
			}
		}
		else if (bean instanceof NamedParameterJdbcDaoSupport) {
			if (this.dataSource != null) {
				((NamedParameterJdbcDaoSupport) bean).setDataSource(this.dataSource);
			}
			else if (this.jdbcTemplate != null) {
				((NamedParameterJdbcDaoSupport) bean).setJdbcTemplate(this.jdbcTemplate);
			}
			else if (this.namedParameterJdbcTemplate != null) {
				((NamedParameterJdbcDaoSupport) bean)
						.setNamedParameterJdbcTemplate(this.namedParameterJdbcTemplate);
			}
		}

		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		return bean;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
		return namedParameterJdbcTemplate;
	}

	public void setNamedParameterJdbcTemplate(
			NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}

}
